#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include "typedef.h"
#include "os_tick.h"
#include "fifo.h"
#include "usart_driver.h"
#include "work.h"
#include "letter-shell/shell_cfg.h"
#include "letter-shell/shell.h"
#include "elog.h"
#include "shell_bsp.h"


#define SHELL_LOG   COM_USART3


struct shell_log_s
{
    SysTick_t shell_tick;
    Shell shell;
    char shell_buffer[512];
};

static struct shell_log_s shell_log={.shell_tick=0};

/******************************** log *******************************************/
/******************************** log *******************************************/
/******************************** log *******************************************/
void log_bsp_level(const char * format, ...)
{
    char str[510]={0};
	int length=0;
	va_list args;
	va_start (args, format);
	length = vsnprintf(str, sizeof(str), format, args);
	va_end (args);

	if(length>0)
		com_dma_send_data(SHELL_LOG,(u8*)str,length);
}
void log_init(void)
{
#ifdef ELOG_OUTPUT_ENABLE
    /* initialize EasyLogger */
    elog_init();
    /* set EasyLogger log format */
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);// & ~(ELOG_FMT_T_INFO | ELOG_FMT_P_INFO)
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_FUNC | ELOG_FMT_T_INFO | ELOG_FMT_P_INFO));
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL & ~(ELOG_FMT_FUNC | ELOG_FMT_T_INFO | ELOG_FMT_P_INFO));
    elog_set_filter_tag_lvl("DDD",ELOG_LVL_DEBUG);
    /* start EasyLogger */
    elog_start();
#endif
}
void log_com_write(const char *data, int length)
{
    com_dma_send_data(SHELL_LOG,(u8*)data,length);
}
const char *log_timestamp_time(void)
{
    static char time_str[32]={0};
    time_t sec = sys_timestamp_get();
    SysTick_t msec = sys_timestamp_msec_get();
    int length=strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&sec));
    snprintf(time_str+length,sizeof(time_str)-length,":%d", msec);
    return time_str;
}
void log_level_set(u8 level)
{
#ifdef ELOG_OUTPUT_ENABLE
    elog_set_filter_lvl(level);
#endif
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),log_level_set,log_level_set,log level set);

void log_test(void)
{
    /* test log output for all level */
    log_a("Hello EasyLogger!");
    log_e("Hello EasyLogger!");
    log_w("Hello EasyLogger!");
    log_i("Hello EasyLogger!");
    log_d("Hello EasyLogger!");
    log_v("Hello EasyLogger!");
    elog_raw("Hello EasyLogger!\r\n");
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),log_test,log_test,elog test);

/******************************** shell *******************************************/
/******************************** shell *******************************************/
/******************************** shell *******************************************/

#ifdef LETTER_SHELL_ENABLE
signed short shell_bsp_write(char * data,unsigned short len)
{
    len=com_dma_send_data(SHELL_LOG,(u8*)data,len);
    return len;
}
signed short shell_bsp_read(char * data, unsigned short len)
{
    struct FIFO_S * Q = com_dma_rx_fifo_get(SHELL_LOG);
    if(fifo_is_empty(Q))
        return 0;
    data[0]=fifo_get_data(Q,0);
    fifo_discard_one(Q);
    return 1;
}
void shell_work(unsigned int data)
{
    if (0 == systick_get_difference_assign(&shell_log.shell_tick, Tnms(97)))
        return;
    shellTask((void *)data);
}
int func1(int i,char ch, char *str)
{
    log_d("input \r\nint : %d  \r\nchar :%c  \r\nstring:%s \r\n",i,ch,str);
    return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),func1,func1,func1 test);

int func2(int argc , char * argv[])
{
    log_dbg("func2 \r\n");
    for(int i=1; i<argc; i++)
        log_d("%s \r\n",argv[i]);
    return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),func2,func2,func1 test);
#endif
void shell_init(void)
{
#ifdef LETTER_SHELL_ENABLE
    shell_log.shell.write = shell_bsp_write;
    shell_log.shell.read = shell_bsp_read ;
    shellInit(&shell_log.shell,shell_log.shell_buffer,sizeof(shell_log.shell_buffer));
    work_add_tail(shell_work,(unsigned int)&shell_log.shell);
#endif
}

//__attribute__((constructor))
void shell_bsp_init(void)
{
    com_dma_usart_init(SHELL_LOG,COM_BR_115200,OPTIONAL_NULL);;//初始化串口
    log_init();
    shell_init();
}

